
#ifndef _NEBULA_SDK__SERVICEBASE_H_
#define _NEBULA_SDK__SERVICEBASE_H_

#include <stdarg.h>

#include <string>

#include "Service.h"
#include "ServiceFactory.h"
#include "Logger.h"

namespace nebula { namespace sdk {

class IRequest;

//helpers for register service to vessel in an easy manner
struct SpecServiceRegistry;

typedef void (*ServiceLoader)(SpecServiceRegistry*);
typedef bool (*Initializer)  ();
typedef void (*Finalizer)    ();


struct SpecServiceRegistry
{
	virtual void RegisterService   (const char* name) = 0;
	virtual bool BindServiceFactory(IServiceFactory*) = 0;
	virtual ~SpecServiceRegistry();
};

struct ServiceRegistry
{
	static ServiceRegistry* GetInst();

	virtual void RegisterService(const char* name, IServiceFactory* ptr) = 0;
	virtual void DynamicService (ServiceLoader, IServiceFactory*) = 0;

	virtual void RegisterGolobalInitializer(Initializer) = 0;
	virtual void RegisterGolobalFinalizer  (Finalizer)   = 0;

	virtual ~ServiceRegistry();
};

template<typename _TYPE>
struct StaticServiceRegistor
{
	StaticServiceRegistor(const char* name)
	{
		ServiceAutoFactory<_TYPE> factory;
		ServiceRegistry::GetInst()->RegisterService(name, &factory);
	}
};

template<typename _TYPE>
struct DynamicServiceRegistor
{
	DynamicServiceRegistor(ServiceLoader loader)
	{
		ServiceAutoFactory<_TYPE> factory;
		ServiceRegistry::GetInst()->DynamicService(loader, &factory);
	}
};

struct InitializerRegistor
{
	InitializerRegistor(Initializer proc)
	{
		ServiceRegistry::GetInst()->RegisterGolobalInitializer(proc);
	}
};

struct FinalizerRegistor
{
	FinalizerRegistor(Finalizer proc)
	{
		ServiceRegistry::GetInst()->RegisterGolobalFinalizer(proc);
	}
};

#define REGISTOR_VARNAME_(token, name) __registor_ ## token(name)
#define REGISTOR_VARNAME(token, name)  REGISTOR_VARNAME_(token, name)

#define REGISTER_SERVICE(name, service) \
	static ::nebula::sdk::StaticServiceRegistor<service>  REGISTOR_VARNAME(__LINE__, name)

#define DYN_REGISTOR_VARNAME_(token, p1) __registor_ ## token(p1)
#define DYN_REGISTOR_VARNAME(token, p1)  DYN_REGISTOR_VARNAME_(token, p1)
#define DYNAMIC_SERVICE(service, loader) \
	static ::nebula::sdk::DynamicServiceRegistor<service> DYN_REGISTOR_VARNAME(__LINE__, loader)

#define REGISTER_INITILIZER(proc) static ::nebula::sdk::InitializerRegistor __registor_init(proc);
#define REGISTER_FINALIZER(proc)  static ::nebula::sdk::FinalizerRegistor   __registor_fina(proc);


class ServiceBase : public IService
{
public:
	ServiceBase();
	virtual ~ServiceBase();

public:
	//Event handlers:
	//The following 4 functions must be implemented by client
	virtual NEBULA_ERROR_CODE OnInitialize () = 0;
	virtual NEBULA_ERROR_CODE OnStart      () = 0;
	virtual void              OnStop       () = 0;
	virtual void              OnFinalize   () = 0;

	//All these state transferring handler functions should not blocking
	// since the state transferring procedures are exclusive
	virtual void OnConfiguring    ();
	virtual void OnConfigured     ();
	virtual void OnAboutToPausing ();
	virtual void OnPausing        ();
	virtual void OnResuming       ();
	virtual void OnAboutToRetiring();
	virtual void OnRetiring       ();
	virtual void OnRetired        ();

	virtual bool IsOverload  ();
	virtual bool IsUnderload ();

public:
	//class scope utilities
	//Service basic information access
	const char*    GetName ();
	IServiceAgent* GetAgent();
	Logger*	       GetLogger();

	//debug-log tools
	void pverbose(const char* fmt, ...);
	void pinfo   (const char* fmt, ...);
	void perror  (const char* fmt, ...);

	//transaction/tracking log
	void tlog    (ITask *, const char* fmt, ...);

public:
	// agent API shortcuts

	inline ServiceState GetServiceState()
	{	return _agent->GetServiceState(); }
	inline NEBULA_ERROR_CODE RegisterPushSlot(const char* name, TaskAllocator alloc, ITodoTaskQueue** queue)
	{	return _agent->RegisterPushSlot(name, alloc, queue); }
	inline NEBULA_ERROR_CODE RegisterPopSlot(const char* name, IDoneTaskQueue** queue)
	{	return _agent->RegisterPopSlot(name, queue); }
	inline NEBULA_ERROR_CODE RegisterQuerySlot(const char* name, QuerySlotHandler handler)
	{	return _agent->RegisterQuerySlot(name, handler); }
	inline NEBULA_ERROR_CODE RegisterDeleteSlot(const char* name, DeleteSlotHandler handler)
	{	return _agent->RegisterDeleteSlot(name, handler); }
	inline NEBULA_ERROR_CODE RegisterUpdateSlot(const char* name, TaskAllocator alloc, UpdateSlotHandler handler)
	{	return _agent->RegisterUpdateSlot(name, alloc, handler); }
	inline NEBULA_ERROR_CODE ServiceConfiguring()
	{	return _agent->ServiceConfiguring(); }
	inline NEBULA_ERROR_CODE ServiceConfigured()
	{	return _agent->ServiceConfigured(); }
	inline NEBULA_ERROR_CODE ServiceError()
	{	return _agent->ServiceError(); }
	inline NEBULA_ERROR_CODE NeedConfig(const char* configurations)
	{	return _agent->NeedConfig(configurations); }
	inline unsigned long GetTodoQueueSize()
	{	return _agent->GetTodoQueueSize(); }
	inline unsigned long GetTodoQueueDoingCount()
	{	return _agent->GetTodoQueueDoingCount(); }
	inline unsigned long GetDoneQueueSize()
	{	return _agent->GetDoneQueueSize(); }
	inline unsigned long GetTodoQueueTraffic()
	{	return _agent->GetTodoQueueTraffic(); }
	inline unsigned long GetDoneQueueTraffic()
	{	return _agent->GetDoneQueueTraffic(); }

public:
	//Do NOT override these functions unless you can handle
	// the interaction between service and the frameworks properly,
	// override the OnXXX event handlers instead.
	NEBULA_ERROR_CODE Initialize (const char*, IServiceAgent*);
	void              Finalize   ();
	NEBULA_ERROR_CODE Start      ();
	void              Stop       ();

protected:
	NEBULA_ERROR_CODE DoInitialize (const char*, IServiceAgent*);
	void              DoFinalize   ();
	NEBULA_ERROR_CODE DoStart      ();
	void              DoStop       ();

protected:
	NEBULA_ERROR_CODE SetFlowControlMinThroughput (unsigned long); // default to 1000
	NEBULA_ERROR_CODE SetFlowControlOverloadCoeff (double);        // default to 1.0
	NEBULA_ERROR_CODE SetFlowControlUnderloadCoeff(double);        // default to 0.8
	unsigned long     GetFlowControlMinThroughput () const { return _min_throughput;  }
	double            GetFlowControlOverloadCoeff () const { return _overload_coeff;  }
	double            GetFlowControlUnderloadCoeff() const { return _underload_coeff; }

private:
	std::string       _name;
	IServiceAgent*    _agent;
	Logger*           _logger;

	unsigned long     _min_throughput;
	double            _overload_coeff;
	double            _underload_coeff;
};

}} // end of nebula::sdk

#endif // _NEBULA_SDK__SERVICEBASE_H_

